using System;
using System.IO;
using System.Text;
using System.IO.Ports;
using System.Threading;
using System.Collections;
using System.Collections.Generic;

using Microsoft.Win32;

namespace repragator
{
	public class Serial
	{
		public event DebugMessageHandler DebugMessageEvent;
		
		public bool IsConnect
		{
			get
			{
				if (port == null)
					return false;
				
				return this.port.IsOpen;
			}
		}
		
		private SerialPort port;
		private Thread feedbackThread;
		private bool connected = false;
		
		public Serial ()
		{
			this.feedbackThread = new Thread(new ThreadStart(this.FeedbackThread));
		}
		
		public bool Connect(string port, int baud)
		{
			if (this.port != null)
				if (this.port.IsOpen)
					this.port.Close();
					
			this.port = new SerialPort(port, baud, Parity.None, 8, StopBits.One);
			
			this.connected = true;
			
			this.port.Open();
			
			this.feedbackThread.Start();
			
			this.Send("M105");
			
			if (this.port == null || !this.port.IsOpen)
				throw new Exception(string.Format("Could not connect to {0} at {1}", port, baud));
			
			return this.port.IsOpen;
		}
		
		public void Disconnect()
		{
			this.feedbackThread.Abort();
			
			this.connected = false;
			
			if (this.port != null)
				this.port.Close();
		}
		
		public void Send(string data)
		{
#if DEBUG
			this.DebugMessageEvent(data);
#endif		
			if (this.port != null && this.port.IsOpen)
				this.port.Write((string)data + "\n");
		}
		
		public void FeedbackThread()
		{
			byte tempByte;
			string feedback = string.Empty;
			
			using (FileStream fs = new FileStream(Path.GetTempPath() + "repragator.tmp", FileMode.Open, FileAccess.Write, FileShare.ReadWrite))
			{
				using (StreamWriter writer = new StreamWriter(fs))
				{
					writer.AutoFlush = true;
					
					while (this.connected)
					{
						feedback = string.Empty;
						
						while (this.port.BytesToRead > 0)
						{
							tempByte = (byte)this.port.ReadByte();
							
							feedback += (char)tempByte;
						}
						
						if (feedback != string.Empty && feedback != "ok\n")
							writer.Write(feedback);
					}
				}
			}
		}
		
		public string[] ScanPorts()
		{
			List<string> ports = new List<string>();
			
			switch (Environment.OSVersion.Platform)
			{
			case PlatformID.MacOSX:
			case PlatformID.Unix:
			{
				foreach (string search in new string[] { "ttyACM*", "ttyUSB*" })
				{
					foreach (string port in Directory.GetFiles("/dev/", search))
					{
						ports.Add(port);	
					}
				}
			}
				break;
			case PlatformID.Win32NT:
			case PlatformID.Win32S:
			case PlatformID.Win32Windows:
			case PlatformID.WinCE:
			{
#if WINDOWS
				RegistryKey root = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Default).OpenSubKey("HARDWARE\\DEVICEMAP\\SERIALCOMM");
				if (root.ValueCount <= 0)
					break;
				
				foreach (string name in root.GetValueNames())
				{
					ports.Add((string)root.GetValue(name));	
				}
#endif
			}
				break;
			default:
				break;
			}
			
			return ports.ToArray();
		}
	}
}